package mediator;

import java.awt.Color;
import java.awt.GraphicsConfiguration;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Vector;

import javax.swing.JOptionPane;

import objectsDiagram.Condition;
import objectsDiagram.Flow;
import objectsDiagram.Fluent;
import objectsDiagram.State;
import objectsDiagram.Task;

import lts.LTSException;
import main.LTSA;
import flwa_to_fsp.FLWAtoFSP;
import guiWindows.GUICreateProperties;
import guiWindows.MainWindow;
import guiWindows.PanelArea;

public class AddPropertyMediator implements ActionListener{
	private GUICreateProperties guiCreateProperty;
	private PanelArea panelArea;
	private String yawlFile;
	private FLWAtoFSP t_info;
	private LinkedList<Fluent> listFluents;
	private MainWindow mainWindow;
	private ShowPropertyMediator showPropertyMediator;
	private Vector<Task> vectorTasks;
	private Vector<Condition> vectorCondition;
	private Vector<Flow> vectorFlow;

	public AddPropertyMediator(Vector<Task> newVectorTask,LinkedList<Fluent> newListFluent,String newYawlFile){
		this.yawlFile = newYawlFile;
		this.listFluents = newListFluent;
		this.vectorTasks = newVectorTask;
		this.guiCreateProperty = new GUICreateProperties(this);
	}

	public PanelArea addNewAreaPanel(){
		return this.guiCreateProperty.addNewAreaPanel();
	}

	public void clearProperties(){
		this.guiCreateProperty.clearProperties();
	}

	@SuppressWarnings("unchecked")
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == guiCreateProperty.getAddButton()){
			guiCreateProperty.getAreasPanel().setVisible(false);
			guiCreateProperty.addNewAreaPanel();
			guiCreateProperty.getAreasPanel().setVisible(true);
			guiCreateProperty.getDeleteButton().setEnabled(true);
			guiCreateProperty.getAddButton().setEnabled(true);
			guiCreateProperty.getCheckPropertyButton().setEnabled(true);
		}
		if(e.getSource()== guiCreateProperty.getDeleteButton()){
			for(int i=0;i<guiCreateProperty.getListPanelAreas().size();i++){
				if(guiCreateProperty.getListPanelAreas().get(i).getCheckBox().isSelected()){
					guiCreateProperty.getListPanelAreas().get(i).setVisible(false);
					guiCreateProperty.getListPanelAreas().get(i).removeAll();
					guiCreateProperty.getListPanelAreas().remove(i);
					for(int j=i;j<guiCreateProperty.getListPanelAreas().size();j++){
						guiCreateProperty.getListPanelAreas().get(j).getLabelArea().setText(""+(j+1));
					}
					guiCreateProperty.setNumberProperty(guiCreateProperty.getNumberProperty()-1);
					i--;
					if(guiCreateProperty.getListPanelAreas().size()==0){
						guiCreateProperty.getDeleteButton().setEnabled(false);
						guiCreateProperty.getCheckPropertyButton().setEnabled(false);
					}
				}	
			}
		}
		if(e.getSource()==guiCreateProperty.getCheckPropertyButton()){
			if(isAnyPropertyChecked()){
				try {
					StringBuffer text = compilingModel();
					parsingInfoFile(text);
					modifyYNETProcess(text);
					System.out.println(text.toString());
					verification(text);
				} catch (Exception e2) {
					e2.printStackTrace();
					JOptionPane.showMessageDialog(null, "Error checking properties ");
				}
			}else{
				JOptionPane.showMessageDialog(null, "No property was checked");
			}
		}
		if(e.getSource()==guiCreateProperty.getBackButton()){
			Object[] arrayTrace = this.mainWindow.getTrace();
			if(arrayTrace != null){
				LinkedList<State> traceStateList = (LinkedList<State>)arrayTrace[0];
				LinkedList<Flow> traceFlowList = (LinkedList<Flow>)arrayTrace[1];
				for(State currentState : traceStateList){
					currentState.setColor(Color.BLACK);
					currentState.setInTrace(false);
					this.mainWindow.repaintDiagrams();
				}
				for(Flow currentFlow : traceFlowList){
					currentFlow.setColor(Color.BLACK);
					currentFlow.setInTrace(false);
					this.mainWindow.repaintDiagrams();
				}
			}
			this.showPropertyMediator.getGUIShowProperty().setVisible(true);
		}
	}

	private boolean isAnyPropertyChecked(){
		for(int i=0; i< guiCreateProperty.getListPanelAreas().size();i++){
			if(guiCreateProperty.getListPanelAreas().get(i).getCheckBox().isSelected())
				return true;
		}
		return false;
	}

	private void verification(StringBuffer text) {
		LTSA ltsa = new LTSA(text);
		try{
			ltsa.parse();
			ltsa.compileAll();
			showPropertyMediator = new ShowPropertyMediator(ltsa);
			showPropertyMediator.setVectorTask(this.vectorTasks);
			showPropertyMediator.setVectorCondition(this.vectorCondition);
			showPropertyMediator.setVectorFlow(this.vectorFlow);
			showPropertyMediator.setMainWindow(this.mainWindow);
			showPropertyMediator.showUp();
		}catch (LTSException x) {
			ltsa.displayError(x);
			JOptionPane.showMessageDialog(null, x.getMessage());
		}
	}

	private StringBuffer compilingModel() throws IOException,
	InterruptedException {
		String outputPath = new File("").getAbsolutePath();
		//System.out.println(outputPath);
		String [] cmd = {ConstantsModel.CMD_JAVA,ConstantsModel.CMD_JAR,ConstantsModel.CMD_YAWL2FSP,ConstantsModel.CMD_INFO+outputPath+ConstantsModel.CMD_INFO_FILE,yawlFile,outputPath+ConstantsModel.CMD_OUTPUT_FILE};

		//System.out.println(cmd[0]+" "+cmd[1]+" "+cmd[2]+" "+cmd[3]+" "+cmd[4]+" "+cmd[5]);
		Process p = Runtime.getRuntime().exec(cmd);
		BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
		BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));

		//		String s;
		//		while ((s = stdInput.readLine()) != null) {
		//			System.out.println(s);
		//		}
		p.getErrorStream();
		p.waitFor();


		StringBuffer text = new StringBuffer();
		t_info = FLWAtoFSP.load("flwa2fsp_translation_info");
		text.append(fillingFluents());
		return text;
	}

	private void modifyYNETProcess(StringBuffer text) {
		String newYNETString = "YNET = (i_cond -> o_cond -> YNET_END),\n\nYNET_END = (ended -> YNET_END).";
		int indexStartsYNET = text.indexOf("YNET");
		int indexEndsYNET = text.indexOf("YNET).") + "YNET).".length();
		text.replace(indexStartsYNET, indexEndsYNET, newYNETString);
	}

	private void parsingInfoFile(StringBuffer text) {
		try {
			Thread.sleep(1000);
			File file = new File ("output.lts");
			FileReader fr = new FileReader (file);
			int c;
			while((c=fr.read())!=-1){
				text.append((char)c);
			}
			fr.close();
			text.append(generateAssertions());

			System.out.println("**************************************************************************");
			System.out.println("Here is the output with either fluents or assertions \n");

		}catch(Exception e1){
			e1.printStackTrace();
			JOptionPane.showMessageDialog(null, "Error on parsing the specification");
		}
	}

	private String fillingFluents(){
		String fluents = "";
		for(int i = 0;i<listFluents.size();i++){
			if(listFluents.get(i).getListOn().size()>0 && listFluents.get(i).getListOff().size()>0){
				fluents = fluents + "\nfluent " + listFluents.get(i).getId()+ " = <{";
				for(int j = 0;j<listFluents.get(i).getListOn().size();j++){
					fluents = fluents + " "+((Task)(listFluents.get(i).getListOn().get(j)[0])).getId().toLowerCase()+".";
					if((listFluents.get(i).getListOn().get(j)[1]).toString().compareTo("true")==0){
						fluents = fluents+"start";
					}
					if((listFluents.get(i).getListOn().get(j)[1]).toString().compareTo("false")==0){
						fluents = fluents+"end";
					}
					if(j != listFluents.get(i).getListOn().size()-1){
						fluents = fluents+",";
					}
				}
				fluents = fluents+"},{";
				for(int j = 0;j<listFluents.get(i).getListOff().size();j++){
					fluents = fluents + " "+((Task)(listFluents.get(i).getListOff().get(j)[0])).getId().toLowerCase()+".";
					if((listFluents.get(i).getListOff().get(j)[1]).toString().compareTo("false")==0){
						fluents = fluents+"end";
					}
					if((listFluents.get(i).getListOff().get(j)[1]).toString().compareTo("true")==0){
						fluents = fluents+"start";
					}
					if(j != listFluents.get(i).getListOff().size()-1){
						fluents = fluents+",";
					}
				}
				fluents = fluents+"}>";
			}
		}
		return replaceFLWANames(fluents)+"\n\n";
	}

	private String generateAssertions(){
		String text = "";
		for(int i=0;i<guiCreateProperty.getListPanelAreas().size();i++){
			if(guiCreateProperty.getListPanelAreas().get(i).getCheckBox().isSelected()){
				text = text +"\nassert "+((char)(65))+(i+1)+" = " + replaceFLWANames(getOperatorsParsed(guiCreateProperty.getListPanelAreas().get(i).getArea().getText()));
			}   
		}
		return text+"\n";
	}

	private String replaceFLWANames(String propertyFLWA){
		if(propertyFLWA.length()>0){
			for(int i=0; i<vectorTasks.size();i++){
				propertyFLWA = propertyFLWA.replaceAll(vectorTasks.get(i).getId().toLowerCase()+".start", t_info.fwla_to_fsp(vectorTasks.get(i).getId()+".start"));
				propertyFLWA = propertyFLWA.replaceAll(vectorTasks.get(i).getId().toLowerCase()+".end", t_info.fwla_to_fsp(vectorTasks.get(i).getId()+".end"));
			}
		}
		return propertyFLWA;
	}

	private String getOperatorsParsed(String strToParse){
		String operatorsPersed = strToParse.replace("\\/", "||");
		operatorsPersed = operatorsPersed.replace("/\\", "&&");
		return operatorsPersed;
	}

	public GUICreateProperties getGuiCreateProperties() {
		return this.guiCreateProperty;
	}

	public void setYawlFile(String yawlFile) {
		this.yawlFile = yawlFile;
	}

	public void setVectorTask(Vector<Task> vectorTask) {
		this.vectorTasks = vectorTask;		
	}

	public void setVectorCondition(Vector<Condition> vectorCondition) {
		this.vectorCondition = vectorCondition;
	}

	public void setVectorFlow(Vector<Flow> vectorFlow) {
		this.vectorFlow = vectorFlow;
	}

	public Vector<Task> getVectorTasks() {
		return vectorTasks;
	}

	public void setMainWindow(MainWindow newMainWindow) {
		this.mainWindow = newMainWindow;
	}


}
